package com.chaihu.jpa.service.impl;

import com.chaihu.jpa.repository.BaseRepository;
import com.chaihu.jpa.utils.BeanUtil;
import com.chaihu.jpa.former.MyResultTransformer;
import com.chaihu.jpa.service.BaseService;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;


/**
 *
 * Create By qinzhw
 * 2018年5月8日上午11:11:42
 */
public abstract class BaseServiceImpl<E,ID extends Serializable> implements BaseService<E,ID> {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	@PersistenceContext
	protected EntityManager em;

	public abstract BaseRepository<E, ID> getBaseRepository();


	/**
	 * 根据ID获取某个Entity
	 * @param id
	 * @return
	 */
	@Override
	public E get(ID id) {
		return getBaseRepository().getOne(id);
	}

	/**
	 * 根据ID查找某个Entity（建议使用）
	 * findOne:查询一个不存在的id数据时，返回的值是null.
	 * getOne:查询一个不存在的id数据时，直接抛出异常 ps :最新版本没有此方法
	 */
	@Override
	public E findOne(ID id)  {
		Optional<E> optional = getBaseRepository().findById(id);
		return optional.orElse(null);
	}
	@Override
	public Optional<E> findById(ID id)  {
		return getBaseRepository().findById(id);
	}


	/**
	 * 获取所有的Entity列表
	 * @return
	 */
	@Override
	public List<E> getAll() {
		return getBaseRepository().findAll();
	}

	/**
	 * 获取Entity的总数
	 * @return
	 */
	@Override
	public Long getTotalCount() {
		return getBaseRepository().count();
	}

	/**
	 * 保存Entity
	 * @param entity
	 * @return
	 */
	@Override
	public E save(E entity) {
		return getBaseRepository().save(entity);
	}

	@Override
	public List<E> saveAll(Iterable<E> entitys){
		return getBaseRepository().saveAll(entitys);
	}

	/**
	 * 修改Entity
	 * @param entity
	 * @return
	 */
	@Override
	public E update(E entity) {
		return getBaseRepository().save(entity);
	}

	@Override
	public E update(ID id,E entity) {
		Optional<E> optional = getBaseRepository().findById(id);
		return optional.map(e -> {
			E e1 = BeanUtil.copyPropertiesIgnoreNull(entity, e);
			return getBaseRepository().save(e);
		}).orElse(null);
	}


	/**
	 * 删除Entity
	 * @param entity
	 */
	@Override
	public void delete(E entity) {
		getBaseRepository().delete(entity);
	}

	/**
	 * 根据Id删除某个Entity
	 * @param id
	 */
	@Override
	public void deleteById(ID id) {
		try {
			getBaseRepository().deleteById(id);
		} catch (EmptyResultDataAccessException e) {
			// 如果是ID在DB不存在,不往外抛异常 add shixh 0521
			logger.info("如果是ID在DB不存在,不往外抛异常");
		}

	}

	/**
	 * 删除Entity的集合类
	 * @param entities
	 */
	@Override
	public void deleteAll(Collection<E> entities) {
		getBaseRepository().deleteAll(entities);
	}

	/**
	 * 清空缓存，提交持久化
	 */
	@Override
	public void flush() {
		getBaseRepository().flush();
	}

	/**
	 * 查询某个条件的结果数集
	 * @param spec
	 * @return
	 */
	@Override
	public long count(Specification<E> spec) {
		return getBaseRepository().count(spec);
	}

	/**
	 * 根据查询信息获取某个Entity的列表
	 * @param spec
	 * @return
	 */
	@Override
	public List<E> findAll(Specification<E> spec) {
		return getBaseRepository().findAll(spec);
	}
	/**
	 * 获取Entity的分页信息
	 * @param pageable
	 * @return
	 */
	@Override
	public Page<E> findAll(Pageable pageable){
		return getBaseRepository().findAll(pageable);
	}

	/**
	 * 根据查询条件和分页信息获取某个结果的分页信息
	 * @param spec
	 * @param pageable
	 * @return
	 */
	@Override
	public Page<E> findAll(Specification<E> spec, Pageable pageable) {
		return getBaseRepository().findAll(spec, pageable);
	}
	/**
	 * 根据查询条件和排序条件获取某个结果集列表
	 * @param spec
	 * @param sort
	 * @return
	 */
	@Override
	public List<E> findAll(Specification<E> spec, Sort sort) {
		return getBaseRepository().findAll(spec,sort);
	}


	/********************************原生封装start******************************/
	@Override
	public Page<E> findAll(Map<String, Object> searchParams, PageRequest pageRequest){
		return getBaseRepository().findPageByParams(searchParams, pageRequest);
	}

	@Override
	public <K> Page<K> findAll(Map<String, Object> searchParams, PageRequest pageRequest, Class<K> clz) {
		return getBaseRepository().findPageByParams(searchParams, pageRequest, clz);
	}

	@Override
	public List<E> findAll(Map<String, Object> searchParams,Sort sort) {
		return getBaseRepository().findListByParams(searchParams,sort);
	}

	@Override
	public <K>List<K> findAll(Map<String, Object> searchParams,Sort sort,Class<K> clz) {
		return getBaseRepository().findListByParams(searchParams, sort, clz);
	}

	@Override
	public List<E> findAll(Map<String, Object> searchParams) {
		return getBaseRepository().findListByParams(searchParams);
	}
	/********************************原生封装end******************************/



	@Override
	public Page<E> findPageByNativeSQL(String sql, PageRequest pageRequest){
		return getBaseRepository().findPageByNativeSQL(sql,pageRequest);
	}
	@Override
	public List<E> findListByNativeSQL(String sql, Sort sort){
		return getBaseRepository().findListByNativeSQL(sql,sort);
	}
	@Override
	public <K>Page<K> findPageByNativeSQL(String sql, Class<K> clz, PageRequest pageRequest){
		return getBaseRepository().findPageByNativeSQL(sql,clz,pageRequest);
	}
	@Override
	public <K>List<K> findListByNativeSQL(String sql, Class<K> clz, Sort sort){
		return getBaseRepository().findListByNativeSQL(sql,clz,sort);
	}



	/*************** 增强公共方法 add by qzhw 2019年1月22日 17:47:24 begin **************/
	/**
	 * @author qzhw
	 */
	@Override
	public <K> Page<K> getPageVo(String sql, PageRequest pageable, Class<K> clazz) {
		Query query = em.createNativeQuery(sql);
		query.setFirstResult(pageable.getPageSize()*pageable.getPageNumber());
		query.setMaxResults(pageable.getPageSize());
		query.unwrap(SQLQuery.class).setResultTransformer(new MyResultTransformer(clazz));
		List<K> content = query.getResultList();
		StringBuffer countSql = new StringBuffer("select count(1) from( ").append(sql).append(" ) as countTmp");
		Number conut = (Number) em.createNativeQuery(countSql.toString()).getSingleResult();
		PageImpl<K> page = new PageImpl<K>(content, pageable, conut.intValue());
		return page;
	}
	@Override
	public <K> List<K> getListVo(String sql, Class<K> clazz) {
		Query query = em.createNativeQuery(sql);
		query.unwrap(SQLQuery.class).setResultTransformer(new MyResultTransformer(clazz));
		List<K> content = query.getResultList();
		return content;
	}

	@Override
	public List<Map<String, Object>> getMap(String sql) {
		Query query = em.createNativeQuery(sql);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		return query.getResultList();
	}
	@Override
	public List<List<Object>> getList(String sql) {
		Query query = em.createNativeQuery(sql);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);
		return query.getResultList();
	}

	@Override
	public <K> Page<K> findPageByNativeSQLAndParams(String sql, Map<String, Object> searchParams, Class<K> clz,PageRequest pageRequest) {
		return getBaseRepository().findPageByNativeSQLAndParams(sql, searchParams, clz, pageRequest);
	}

	@Override
	public <K> List<K> findListByNativeSQLAndParams(String sql, Map<String, Object> searchParams, Class<K> clz,Sort sort) {
		return getBaseRepository().findListByNativeSQLAndParams(sql, searchParams, clz, sort);
	}

	@Override
	public <K> Page<K> findPageByJPQL(String jpql, Map<String, Object> searchParams, Class<K> clz,PageRequest pageRequest) {
		return getBaseRepository().findPageByJPQL(jpql, searchParams, clz, pageRequest);
	}

	@Override
	public <K> List<K> findListByJPQL(String jpql, Map<String, Object> searchParams, Class<K> clz, Sort sort) {
		return getBaseRepository().findListByJPQL(jpql, searchParams, clz, sort);
	}
	/*************** 增强公共方法 add by qzhw 2019年1月22日 17:47:24 end **************/

}